(function (fruit, util, ui, viewEngine) {
    /**
     * @class fruit.ui.Component
     * @type {*}
     */
    var Component = fruit.define('fruit.ui.Component', fruit.ui.Element, {
        statics: {
            /**
             * Static method to create a component.
             * @param view
             * @returns {view.__comp__}
             */
            create: function (view) {
                if (view) {
                    var type = view.type;
                    var props = view.props;
                    var comp = view.__comp__;
                    if (comp) {
                        return new comp(props);
                    }
                    else if (type) {
                        comp = view.__comp__ = util.getByPath(type);
                        return new comp(props);
                    }
                    else {
                        comp = view.__comp__ = ui.define({
                            view: view
                        });
                        return new comp(props);
                    }
                }
            }
        },
        properties: {
            model: {
                getter: function () {
                    return this._model || this._inheritedModel;
                },
                setter: function (value) {
                    if (this._model !== value) {
                        var model = value;
                        var modelType = this.model.config.type;
                        if (modelType && !(model instanceof modelType)) {
                            model = modelType.$type ? new modelType(model) : modelType(model);
                        }
                        this._model = model;
                        this.notifyPropertyChanged('model');
                        this.$().model(model);
                    }
                }
            },
            template: {
                value: null
            }
        },
        methods: {
            init: function (options) {
                this._defaultInit(options);
            },
            /**
             * template method.after construction
             */
            onInit: function () {

            },
            _defaultInit: function (inOptions, inOwner) {
                this._bindings = {};
                viewEngine.resolve(this, null, inOwner);
                var root = this.$();
                this._style = root._style;
                this._class = root._class;
                ui.Element.registerInstance(this);
                this.setAll(inOptions);
                this.onInit();
            },
            _init: function (inElement, inOwner) {
                this._bindings = {};
                viewEngine.resolve(this, inElement, inOwner);
                var root = this.$();
                this._style = root._style;
                this._class = root._class;
                ui.Element.registerInstance(this);
                this.onInit();
            },
            _inheritModel: function (model) {
                if (this._model === undefined && this._inheritedModel !== model) {
                    var modelType = this.model.config.type;
                    if (modelType && !(model instanceof modelType)) {
                        model = modelType.$type ? new modelType(model) : modelType(model);
                    }
                    this._inheritedModel = model;
                    this.notifyPropertyChanged('model');
                }

                this.$()._inheritModel(model);
            },
            /**
             * Set the view of current component.
             * @param view
             */
            setView: function (view) {
                viewEngine.dispose(this);
                this.$view = view;
                viewEngine.resolve(this);
            },
            /**
             * Destroy current component.
             */
            destroy: function () {
                this.inherited();
            },
            /**
             * Batch set properties for current component.
             * @param props
             * @returns {*}
             */
            setAll: function (props) {
                this.inherited(props);
                return this;
            }
        }
    });

    fruit.ui.define = function (t, p, m) {
        var type = null, parents = null, members = null;
        if (typeof(t) === 'string') {
            type = t;
            parents = p;
            members = m;
        }
        else {
            parents = t;
            members = p;
        }

        if (parents instanceof Function) {
            parents = [parents];
        }
        else if (!(parents instanceof Array)) {
            members = parents;
            parents = [];
        }

        members = members || {};

        var parent = parents[0] || Component;
        var events = members.events;
        var properties = members.properties;
        var methods = members.methods;
        var view = members.view;
        var triggers = members.triggers;

        var clazz = type ?
            fruit.define(type, parent, {
                events: events,
                properties: properties,
                methods: methods
            }) :
            fruit.define(parent, {
                events: events,
                properties: properties,
                methods: methods
            });

        if (view) {
            clazz.prototype.$view = view;
        }


        clazz.prototype.$events = events;
        clazz.prototype.$triggers = triggers;

        return clazz;
    };

})(fruit, fruit.util, fruit.ui, fruit.ui.viewEngine);
